package com.bookseek.xreader.service.dk;

import android.database.Cursor;

import com.bookseek.xreader.consts.XreaderConts;
import com.bookseek.xreader.dbhelper.DbSessionUtils;
import com.bookseek.xreader.po.FtsBdocPo;
import com.bookseek.xreader.po.FtsBookPo;
import com.bookseek.xreader.po.TMetaPo;
import com.bookseek.xreader.utils.DLog;
import com.bookseek.xreader.utils.JkhlUtils;
import com.bookseek.xreader.utils.MiniDataUtils;
import com.bookseek.xreader.utils.OkHttpUtils;
import com.bookseek.xreader.vo.FtsBdocVo;
import com.bookseek.xreader.vo.FtsBookVo;
import com.bookseek.xreader.vo.mock.FanYiVo;
import com.google.gson.reflect.TypeToken;

import org.greenrobot.greendao.database.Database;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class FtsBookService extends BaseFtsService {
    private static FtsBookService instance;

    private static String TAB_BOOK = "book";

    private FtsBookService(){}
    public static FtsBookService getInstance(){
        if(instance == null){
            synchronized (FtsBookService.class){
                if(instance == null){
                    instance = new FtsBookService();
                }
            }
        }
        return instance;
    }


    public int insertBatch(List<FtsBookPo> pos){
        Long startTm = System.currentTimeMillis();
        String colNameStr = "rowid,cname,cont,bid,cid";
        Integer colNameLen = colNameStr.split(",").length;
        StringBuffer sql = new StringBuffer(" INSERT INTO ").append(TAB_BOOK).append(" ( ");
        sql.append(colNameStr).append(" ) VALUES ");
        Object[] args = new Object[pos.size() * colNameLen];
        List<String> prepareList = new ArrayList<>(pos.size());
        int position = 0;
        Set<Long> addIds = new HashSet<>();
        for(int i = 0;i<pos.size();i++){
            List<String> pres = new ArrayList<>();
            FtsBookPo po = pos.get(i);
            //rowid,bname,bauthor,cname,cont,
            // bchao,btype,cimg,bid,cid,bphk,cphk
            for(int j = 0 ;j < colNameLen;j++){
                pres.add("?");
                Object val = "";
                if(j == 0){
                    //rowid
                    val = po.cid;
                    addIds.add(po.cid);
                }else if(j == 1){
                    //bname
                    val = JkhlUtils.toStr(po.cname);
                }else if(j == 2){
                    //bauthor
                    val = JkhlUtils.toStr(po.cont);
                }else if(j == 3){
                    //cname
                    val = JkhlUtils.toStr(po.bid);
                }else if(j == 4){
                    //cont
                    val = JkhlUtils.toStr(po.cid);
                }
                args[position] = val;
                position++;
            }
            String preStr = "("+String.join(",",pres)+")";
            prepareList.add(preStr);
        }
        sql.append(String.join(",",prepareList));
        String execSql = sql.toString();
        // DLog.info("execSql=",execSql);
        // DLog.info("args=",OkHttpUtils.gson.toJson(args));

        Database db = DbSessionUtils.genDaoSession().getDatabase();
        db.beginTransaction();
        try{
            db.execSQL(execSql,args);
            db.setTransactionSuccessful();
        }catch (Exception e){
            e.printStackTrace();
            DLog.error("SQL 执行异常 ",e.getMessage(),addIds.size(),"pos.size()=",pos.size());
        }finally {
            db.endTransaction();
        }
        Long endTm = System.currentTimeMillis();
        Long minCid = pos.stream().map(d->d.cid).sorted().findFirst().orElse(null);
        DLog.info("批量插入数据条数=minCid=>",minCid,pos.size()," 耗时=",endTm-startTm," ms");
        return pos.size();
    }

    public List<FtsBookVo> getBookAllChapter(Long bookid){
        Long startTm = System.currentTimeMillis();
        List<FtsBookVo> datas = new ArrayList<>();
        StringBuffer sql  = new StringBuffer("select * from ");
        sql.append(TAB_BOOK).append(" where bid = '").append(bookid).append("'");
        Database db  = DbSessionUtils.genDaoSession().getDatabase();
        Cursor cursor = db.rawQuery(sql.toString(), null);
        try{
            // 遍历 Cursor 处理结果
            if (cursor.moveToFirst()) {
                do {
                    String cname   = cursor.getString(cursor.getColumnIndexOrThrow("cname"));
                    String cont    = cursor.getString(cursor.getColumnIndexOrThrow("cont"));
                    Long bid   = cursor.getLong(cursor.getColumnIndexOrThrow("bid"));
                    Long cid   = cursor.getLong(cursor.getColumnIndexOrThrow("cid"));
                    DLog.info("cid=>",cid,"bid=>",bid,"cname=>",cname);
                    FtsBookVo bookVo = new FtsBookVo();
                    bookVo.cid = cid;
                    bookVo.bid = bid;
                    bookVo.cname = JkhlUtils.toStr(cname).replace(" ","");
                    bookVo.bcontList = new ArrayList<>();
                    //分割成段落
                    String[] ptexts = JkhlUtils.toStr(cont).split("\\|");
                    for(String ptext : ptexts){
                        FanYiVo fanVo = new FanYiVo();
                        fanVo.t = 0;
                        //空格合并
                        fanVo.x = ptext.replaceAll(" ","");
                        bookVo.bcontList.add(fanVo);
                    }
                    datas.add(bookVo);
                } while (cursor.moveToNext());
            }
        }finally {
            if(cursor != null && !cursor.isClosed()){
                DLog.info("testQueryTime 关闭 cursor ");
                cursor.close();
            }
        }
        Long endTm = System.currentTimeMillis();
        DLog.info("fts5datas size=",datas.size()," 查询耗时：",endTm-startTm," ms",OkHttpUtils.gson.toJson(datas.get(0)));
        return datas;
    }

    public int saveFtsBook(List<FtsBookPo> pos){
        if(pos == null || pos.size() == 0){
            return 0;
        }
       List<FtsBookPo> okPos = pos.stream().filter(d->d.cid != null).collect(Collectors.toList());
       Set<Long> cids = okPos.stream().map(d->d.cid).collect(Collectors.toSet());
       Set<Long> dbCids = getExistRowid(cids,TAB_BOOK);
       List<FtsBookPo> addPos = okPos.stream().filter(d->!dbCids.contains(d.cid)).collect(Collectors.toList());
       int addSize = addPos.size();
       int okSize = okPos.size();
        DLog.info("okSize=",okSize," addSize=",addSize);
        List<List<FtsBookPo>> pagePos = JkhlUtils.pageDatas(addPos, XreaderConts.BOOK_DB_BATCH_SIZE);
        int splitCount = pagePos.size();
        Long startTm = System.currentTimeMillis();
        int countNum = 0;
        for(int page  = 0 ;page < splitCount;page++){
            DLog.info("addSize=",addSize,"page=",page,"splitCount=",splitCount);
            List<FtsBookPo> pageDatas = pagePos.get(page);
            countNum += insertBatch(pageDatas);
        }
        Long endTm = System.currentTimeMillis();
        DLog.info("okSize=",okSize," addSize=",addSize," 插入耗时 ",endTm-startTm," ms");
        return countNum;
    }


    public void dealDownDataAsync(TMetaPo po, byte[] datas){
        if(datas == null || datas.length == 0){
            return;
        }
        OkHttpUtils.getInstance().getThreadPool().execute(()->{
            DLog.info("解密数据==》");
            long aTm = System.currentTimeMillis();
            String jsonpText = new String(datas, StandardCharsets.UTF_8);
            String srcJson = MiniDataUtils.aesDecryptCBCWithIvFromBase64SafeUrlJSONP(jsonpText);
            long bTm = System.currentTimeMillis();
            DLog.info(datas.length/1024,"KB 数据 ,解密耗时 ",bTm-aTm," ms");
            List<FtsBookPo> bdocPos = OkHttpUtils.gson.fromJson(srcJson,new TypeToken<List<FtsBookPo>>(){}.getType());
            long cTm = System.currentTimeMillis();
            DLog.info(datas.length/1024,"KB 数据 ,JSON耗时 ",cTm-bTm," ms"," bdocPos.size=",bdocPos.size(),OkHttpUtils.gson.toJson(bdocPos.get(0)));
            saveFtsBook(bdocPos);
            long tTm = System.currentTimeMillis();
            DLog.info("处理byte[] db 总耗时",tTm-cTm," ms"," bdocPos.size=",bdocPos.size()," 总耗时=",tTm-aTm," ms");
        });
    }






}
